package de.cwach.svgeditor;

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.logging.Logger;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.KeyStroke;
import javax.swing.filechooser.FileNameExtensionFilter;

import org.apache.batik.util.gui.xmleditor.XMLTextEditor;

public class SVGTexteditor {

	Logger logger = Logger.getLogger("de.cwach.svgeditor.SVGTexteditor");

	private SVGCanvas canvas;
	private XMLTextEditor editor;
	private StringUndoHistory history;
	private JFileChooser fc;

	private File defaultFile;

	public SVGTexteditor(SVGCanvas canvas) {
		this.canvas = canvas;
		editor = new XMLTextEditor();

		history = new StringUndoHistory(20);
		defaultFile = new File("default.svg");
		
		fc = new JFileChooser();
	    FileNameExtensionFilter filter = new FileNameExtensionFilter(
	            "SVG Images", "svg");
	        fc.setFileFilter(filter);
	    

		ErrorListener errorlistener = new ErrorListener() {

			public void notify(String msg) {
				editor.setBackground(new Color(252, 227, 215));
			}
		};

		canvas.addErrorListener(errorlistener);

		Action compileAction = new AbstractAction("compileAction") {
			private static final long serialVersionUID = 0;

			public void actionPerformed(ActionEvent e) {
				userDraw();
			}
		};

		Action clearAction = new AbstractAction("clearAction") {
			private static final long serialVersionUID = 1;

			public void actionPerformed(ActionEvent e) {
				clearEditor();
			}
		};

		Action undoAction = new AbstractAction("undoAction") {
			private static final long serialVersionUID = 2;

			public void actionPerformed(ActionEvent e) {
				undo();
			}
		};

		Action redoAction = new AbstractAction("redoAction") {
			private static final long serialVersionUID = 3;

			public void actionPerformed(ActionEvent e) {
				redo();
			}
		};

		Action demo1Action = new AbstractAction("demo1Action") {
			private static final long serialVersionUID = 4;

			public void actionPerformed(ActionEvent e) {
				loadFile(new File("demo1.svg"));
			}
		};

		Action demo2Action = new AbstractAction("demo2Action") {
			private static final long serialVersionUID = 5;

			public void actionPerformed(ActionEvent e) {
				loadFile(new File("demo2.svg"));
			}
		};
		Action demo3Action = new AbstractAction("demo3Action") {
			private static final long serialVersionUID = 6;

			public void actionPerformed(ActionEvent e) {
				loadFile(new File("demo3.svg"));
			}
		};
		Action demo4Action = new AbstractAction("demo4Action") {
			private static final long serialVersionUID = 7;

			public void actionPerformed(ActionEvent e) {
				loadFile(new File("demo4.svg"));
			}
		};
		Action demo5Action = new AbstractAction("demo5Action") {
			private static final long serialVersionUID = 8;

			public void actionPerformed(ActionEvent e) {
				loadFile(new File("demo5.svg"));
			}
		};
		Action demo6Action = new AbstractAction("demo6Action") {
			private static final long serialVersionUID = 9;

			public void actionPerformed(ActionEvent e) {
				loadFile(new File("demo6.svg"));
			}
		};
		Action demo7Action = new AbstractAction("demo7Action") {
			private static final long serialVersionUID = 10;

			public void actionPerformed(ActionEvent e) {
				loadFile(new File("demo7.svg"));
			}
		};
		
		Action openAction = new AbstractAction("openAction") {
			private static final long serialVersionUID = 11;
			@Override
			public void actionPerformed(ActionEvent arg0) {
				logger.info("open action");
				int r = fc.showOpenDialog(editor);
				if (r==fc.APPROVE_OPTION) {
					loadFile(fc.getSelectedFile());
				}
				
				
			}
		};
		
		Action saveAction = new AbstractAction("saveAction") {
			private static final long serialVersionUID = 12;
			@Override
			public void actionPerformed(ActionEvent arg0) {
				logger.info("save action");
				int r = fc.showSaveDialog(editor);
				if (r==fc.APPROVE_OPTION) {
					writeSVGFile(fc.getSelectedFile(),false);
				}
				
				
				
			}
		};


		editor.getActionMap().put(compileAction.getValue(Action.NAME),
				compileAction);
		editor.getActionMap().put(clearAction.getValue(Action.NAME),
				clearAction);
		editor.getActionMap().put(undoAction.getValue(Action.NAME), undoAction);
		editor.getActionMap().put(redoAction.getValue(Action.NAME), redoAction);
		editor.getActionMap().put(demo1Action.getValue(Action.NAME),
				demo1Action);
		editor.getActionMap().put(demo2Action.getValue(Action.NAME),
				demo2Action);
		editor.getActionMap().put(demo3Action.getValue(Action.NAME),
				demo3Action);
		editor.getActionMap().put(demo4Action.getValue(Action.NAME),
				demo4Action);
		editor.getActionMap().put(demo5Action.getValue(Action.NAME),
				demo5Action);
		editor.getActionMap().put(demo6Action.getValue(Action.NAME),
				demo6Action);
		editor.getActionMap().put(demo7Action.getValue(Action.NAME),
				demo7Action);
		editor.getActionMap().put(openAction.getValue(Action.NAME), openAction);
		editor.getActionMap().put(saveAction.getValue(Action.NAME), saveAction);

		editor.getInputMap().put(
				KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F1, 0),
				compileAction.getValue(Action.NAME));
		editor.getInputMap().put(
				KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F2, 0),
				clearAction.getValue(Action.NAME));
		editor.getInputMap().put(
				KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F4, 0),
				undoAction.getValue(Action.NAME));
		editor.getInputMap().put(
				KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F5, 0),
				redoAction.getValue(Action.NAME));
		editor.getInputMap().put(
				KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F6, 0),
				demo1Action.getValue(Action.NAME));
		editor.getInputMap().put(
				KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F7, 0),
				demo2Action.getValue(Action.NAME));
		editor.getInputMap().put(
				KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F8, 0),
				demo3Action.getValue(Action.NAME));
		editor.getInputMap().put(
				KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F9, 0),
				demo4Action.getValue(Action.NAME));
		editor.getInputMap().put(
				KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F10, 0),
				demo5Action.getValue(Action.NAME));
		editor.getInputMap().put(
				KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F11, 0),
				demo6Action.getValue(Action.NAME));
		editor.getInputMap().put(
				KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F12, 0),
				demo7Action.getValue(Action.NAME));
		editor.getInputMap().put(
				KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_O, java.awt.event.InputEvent.CTRL_DOWN_MASK), openAction.getValue(Action.NAME));
		editor.getInputMap().put(
				KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_S, java.awt.event.InputEvent.CTRL_DOWN_MASK), saveAction.getValue(Action.NAME));
		
		

	}

	/**
	 * Writes a valid svg header and a 100px grid in the given file. The editor
	 * content is appended. The <svg> tag ist closed afterwards.
	 * 
	 * @param file
	 * @param header
	 */
	public void writeSVGFile(File file, boolean header) {
		try {
			// Open file. Overwrite.
			PrintWriter pw = new PrintWriter(file);

			if (header){
			// Write prelude
			// SVG Header
			pw.write("<?xml version=\"1.0\" standalone=\"no\"?>");
			pw
					.write("<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.0\">");
			
			// 100px grid in [0,4000]x[0,4000]
			int maxX = 4000;
			int maxY = 4000;
			int stepX = 100;
			int stepY = 100;

			for (int x = stepX; x <= maxX; x += stepX)
				pw
						.write("<line x1=\""
								+ x
								+ "\" y1=\"0\" x2=\""
								+ x
								+ "\" y2=\""
								+ maxY
								+ "\" style=\"stroke:rgb(211,211,211);stroke-width:1\"/>)");
			for (int y = stepY; y <= maxY; y += stepY)
				pw
						.write("<line y1=\""
								+ y
								+ "\" x1=\"0\" y2=\""
								+ y
								+ "\" x2=\""
								+ maxX
								+ "\" style=\"stroke:rgb(211,211,211);stroke-width:1\"/>)");

			}
			// Write editor content.
			editor.write(pw);
			// Close <svg> Tag from leadin
			if (header) {
			pw.write("</svg>");
			}
			// Close file
			pw.flush();
			pw.close();

		} catch (FileNotFoundException e) {
			notifyErrorListeners("Editor: FileNotFound during write. "
					+ file.toString());
		} catch (IOException e) {
			notifyErrorListeners("Editor: IOException during write. "
					+ e.toString());
		}
	}

	public void loadFile(File file) {

		createUndoPoint();

		try {
			editor.read(new FileInputStream(file), null);
		} catch (FileNotFoundException e) {
			notifyErrorListeners("Editor: FileNotFound during load. "
					+ file.toString());
		} catch (IOException e) {
			notifyErrorListeners("Editor: IOException during load. "
					+ e.toString());
		}

		draw();

	}

	public void clearEditor() {

		createUndoPoint();
		editor.setText("");
		draw();

	}

	public void redo() {

		String s = history.redo(editor.getText());
		if (s != null) {
			editor.setText(s);
			draw();
		}

	}

	public void undo() {
		String s = history.undo(editor.getText());
		if (s != null) {
			editor.setText(s);
			draw();
		}
	}

	public void createUndoPoint() {
		history.setUndoPoint(editor.getText());
	}

	private void notifyErrorListeners(String msg) {

	}

	private void draw() {
		writeSVGFile(defaultFile,true);
		canvas.loadImage(defaultFile);
		editor.setBackground(Color.WHITE);
	}

	public void userDraw() {
		createUndoPoint();
		
		Calendar cal = Calendar.getInstance();
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		
		
		String fname = "log/" + sdf.format(cal.getTime()) + ".svg";
		File f = new File(fname);
		writeSVGFile(f,true);
		
		
		draw();

	}

	public JComponent getEditorSwingComponent() {
		return editor;
	}

}
